home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 1 / Meeting Pearls Vol 1 (1994).iso / installed_progs / util / pgp / pgpamiga / source / keymaint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  39.9 KB  |  1,600 lines

  1. /*    keymaint.c  - Keyring maintenance pass routines for PGP.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     All the source code Philip Zimmermann wrote for PGP is available for
  10.     free under the "Copyleft" General Public License from the Free
  11.     Software Foundation.  A copy of that license agreement is included in
  12.     the source release package of PGP.  Code developed by others for PGP
  13.     is also freely available.  Other code that has been incorporated into
  14.     PGP from other sources was either originally published in the public
  15.     domain or was used with permission from the various authors.  See the
  16.     PGP User's Guide for more complete information about licensing,
  17.     patent restrictions on certain algorithms, trademarks, copyrights,
  18.     and export controls.  
  19.  
  20.     keymaint.c implemented by Branko Lankester.
  21. */
  22.  
  23. #include <stdio.h>
  24. #include <time.h>
  25. #include <stdlib.h>
  26. #include "mpilib.h"
  27. #include "random.h"
  28. #include "crypto.h"
  29. #include "fileio.h"
  30. #include "keymgmt.h"
  31. #include "keymaint.h"
  32. #include "mpiio.h"
  33. #include "charset.h"
  34. #include "language.h"
  35. #include "pgp.h"
  36.  
  37. #if 1 /* def DEBUG */
  38. #include <assert.h>
  39. #else
  40. #define assert(x)
  41. #endif
  42.  
  43. int init_userhash(void);
  44. void endkrent(void);
  45.  
  46. struct userid;
  47. struct signature;
  48.  
  49. struct pubkey {
  50.     struct pubkey *pk_next;
  51.     struct pubkey *pk_hash;            /* hash list for keyID */
  52.     struct userid *pk_userids;
  53.     struct signature *pk_signed;    /* signatures this key made */
  54.     byte pk_keyid[KEYFRAGSIZE];
  55.     byte pk_owntrust;
  56.     byte pk_depth;        /* shortest cert. path to buckstop key */
  57. };
  58.  
  59. struct userid {
  60.     struct userid *uid_next;
  61.     struct pubkey *uid_key;        /* backlink to key */
  62.     struct signature *uid_signatures;
  63.     char *uid_userid;
  64.     byte uid_legit;
  65. };
  66.  
  67. struct signature {
  68.     struct signature *sig_next;        /* list of signatures on a userid */
  69.     struct userid *sig_uid;            /* the userid it signs */
  70.     struct pubkey *sig_from;        /* key that made this signature */
  71.     struct signature *sig_nextfrom;    /* list of sigs made by the same key (sig_from) */
  72.     byte sig_trust;
  73. };
  74.  
  75.  
  76. int maint_list(char *ringfile);
  77. void init_trust_lst(void);
  78. long lookup_by_keyID(FILE *f, byte *srch_keyID);
  79. void show_userid(FILE *f, byte *keyID);
  80.  
  81. static int maintenance(char *ringfile);
  82. static int maint_read_data(char *ringfile);
  83. static int maint_trace_chain(void);
  84. static int trace_sig_chain(struct pubkey *pk, int depth);
  85. static int maint_final(char *ringfile);
  86. static struct pubkey * getpubkey(byte *keyID);
  87. static void setup_trust(void);
  88. static int check_secretkey(FILE *f, long keypos);
  89. static void maint_init_mem(void);
  90. static void maint_release_mem(void);
  91. static VOID * allocn(int size);
  92. static char * store_str(char *str);
  93. static VOID * allocbuf(int size);
  94. static void freebufpool(void);
  95. static void compute_legit(struct userid *id);
  96.  
  97.  
  98. #define    ALLOC_UNIT    4000    /* memory will be allocated in chunks of this size */
  99.  
  100. #define    MAX_DEPTH    8    /* max. value of max_cert_depth */
  101.  
  102. /* returned when trying to do a maintenance pass on a secret keyring or keyfile */
  103. #define    ERR_NOTRUST        -7
  104.  
  105. #define TRUST_MASK        7    /* mask for userid/signature trust bytes */
  106. #define SET_TRUST(b,v)    (*(b) = (*(b) & ~TRUST_MASK) | (v))
  107. #define TRUST_LEV(b)    ((b) & TRUST_MASK)
  108.  
  109. #define    TRUST_FAC(x)    (trust_tbl[TRUST_LEV(x)])
  110.  
  111. #define ctb_type(c)        ((c&CTB_TYPE_MASK)>>2)
  112. /*
  113.  * table for tuning user paranoia index.
  114.  * values represent contribution of one signature indexed by the
  115.  * SIGTRUST of a signature
  116.  */
  117. static int trust_tbl[8];
  118.  
  119. static int marginal_min;
  120. static int complete_min;    /* total count needed for a fully legit key */
  121.  
  122. int marg_min = 2;        /* number of marginally trusted signatures needed for
  123.                            a fully legit key (can be set in config.pgp). */
  124. int compl_min = 1;        /* number of fully trusted signatures needed */
  125.  
  126. char trust_lst[8][16] = {
  127.     "undefined",        /* PSTR("undefined") */
  128.     "unknown",            /* PSTR("unknown") */
  129.     "untrusted",        /* PSTR("untrusted") */
  130.     "<3>",                /* unused */
  131.     "<4>",                /* unused */
  132.     "marginal",            /* PSTR("marginal") */
  133.     "complete",            /* PSTR("complete") */
  134.     "ultimate",            /* PSTR("ultimate") */
  135. };
  136.  
  137. char legit_lst[4][16] = {
  138.     "undefined",
  139.     "untrusted",
  140.     "marginal",
  141.     "complete"
  142. };
  143.  
  144. static int trustlst_len = 9;    /* length of longest trust word */
  145. static int legitlst_len = 9;    /* length of longest legit word */
  146.  
  147. char floppyring[MAX_PATH] = "";
  148. int max_cert_depth = 4;        /* maximum nesting of signatures */
  149.  
  150. static boolean check_only = FALSE;
  151. static boolean mverbose;
  152. static FILE *sec_fp;
  153. static FILE *floppy_fp = NULL;
  154. static int undefined_trust;    /* number of complete keys with undef. trust */
  155.  
  156. /*
  157.  * Update trust parameters in a keyring, should be called after all
  158.  * key management functions which can affect the trust parameters.
  159.  * Changes are done "inplace", the file must be writable.
  160.  */
  161. int
  162. maint_update(char *ringfile)
  163. {
  164.     check_only = mverbose = FALSE;
  165.     return maintenance(ringfile);
  166. }
  167.  
  168. /*
  169.  * Check trust parameters in ringfile
  170.  * options can be:
  171.  *    MAINT_CHECK        check only, don't ask if keyring should be updated
  172.  *    MAINT_VERBOSE    verbose output, shows signature chains
  173.  */
  174. int
  175. maint_check(char *ringfile, int options)
  176. {
  177.     int status;
  178.     char *fixfile;
  179.  
  180.     mverbose = ((options & MAINT_VERBOSE) != 0);
  181.  
  182.     if (moreflag)
  183.         open_more();
  184.     if (*floppyring != '\0' && (floppy_fp = fopen(floppyring, FOPRBIN)) == NULL)
  185.         fprintf(pgpout,PSTR("\nCan't open backup key ring file '%s'\n"),
  186.                 floppyring);
  187.     check_only = TRUE;
  188.     status = maintenance(ringfile);
  189.     if (floppy_fp) {
  190.         fclose(floppy_fp);
  191.         floppy_fp = NULL;
  192.     }
  193.     if (status <= 0) {
  194.         if (status == 0)
  195.             maint_list(ringfile);
  196.         close_more();
  197.         return status;
  198.     }
  199. #ifdef xDEBUG
  200.     if (status > 0 && (options & MAINT_CHECK)) {
  201.         FILE *sav = pgpout;
  202.         if (pgpout = fopen("before.lst", "w")) {
  203.             maint_list(ringfile);
  204.             fclose(pgpout);
  205.         }
  206.         pgpout = sav;
  207.     }
  208. #endif
  209.     /* Inform user of trust parameters to be changed... */
  210.     if (undefined_trust) {
  211.  
  212.         /* If we are just going to check, then exit now... */
  213.         if (options & MAINT_CHECK){
  214.             maint_list(ringfile);
  215.         }
  216.  
  217.         fprintf(pgpout, PSTR("\n%d \"trust parameter(s)\" need to be changed.\n"), 
  218.                      undefined_trust);
  219.  
  220.         if (options & MAINT_CHECK) {
  221.             close_more();
  222.             return status;
  223.         }
  224.  
  225.         fprintf(pgpout, PSTR("Continue with '%s' (Y/n)? "),
  226.             ringfile);
  227.         if (!getyesno('y')) {
  228.             close_more();
  229.             return status;
  230.         }
  231.     }            
  232.  
  233.     /* do the fixes in a scratch file */
  234.     fixfile = tempfile(0);
  235.     if (copyfiles_by_name(ringfile, fixfile) < 0) {
  236.         close_more();
  237.         return -1;
  238.     }
  239.     check_only = mverbose = FALSE;
  240.     if ((status = maintenance(fixfile)) >= 0) {
  241.         maint_list(fixfile);
  242.         fprintf(pgpout, PSTR("\n%d \"trust parameter(s)\" changed.\n"), status);
  243.     }
  244.     close_more();
  245.     if (status > 0 && !(options & MAINT_CHECK)) {
  246.         fprintf(pgpout, PSTR("Update public keyring '%s' (Y/n)? "), ringfile);
  247.         if (getyesno('y'))
  248.             return savetempbak(fixfile, ringfile);
  249.     }
  250.     rmtemp(fixfile);
  251.     return status;
  252. }
  253.  
  254.  
  255. static int
  256. maintenance(char *ringfile)
  257. {
  258.     int status;
  259.     char secretkeyring[MAX_PATH];
  260.     undefined_trust = 0;        /* None so far... */
  261.  
  262.     if (max_cert_depth > MAX_DEPTH)
  263.         max_cert_depth = MAX_DEPTH;
  264.     buildfilename(secretkeyring, SECRET_KEYRING_FILENAME);
  265.     if ((sec_fp = fopen(secretkeyring, FOPRBIN)) == NULL)
  266.         fprintf(pgpout,PSTR("\nCan't open secret key ring file '%s'\n"),
  267.                 secretkeyring);
  268.  
  269.     setkrent(ringfile);
  270.     setup_trust();
  271.     maint_init_mem();
  272.     if (mverbose || verbose)
  273.         fprintf(pgpout, PSTR("\nPass 1: Looking for the \"ultimately-trusted\" keys...\n"));
  274.     status = maint_read_data(ringfile);
  275.     if (sec_fp) {
  276.         fclose(sec_fp);
  277.         sec_fp = NULL;
  278.     }
  279.     if (status < 0)
  280.         goto failed;
  281.  
  282.     if (mverbose || verbose)
  283.         fprintf(pgpout, PSTR("\nPass 2: Tracing signature chains...\n"));
  284.     if ((status = maint_trace_chain()) < 0)
  285.         goto failed;
  286.  
  287.     if (verbose)
  288.         fprintf(pgpout, "\nPass 3: %s keyring...\n",
  289.             (check_only ? "Checking with" : "Updating"));
  290.     if ((status = maint_final(ringfile)) < 0)
  291.         goto failed;
  292.  
  293.     endkrent();
  294.     maint_release_mem();
  295.     return(status+undefined_trust);
  296.  
  297. failed:
  298.     if (verbose)
  299.         fprintf(pgpout, "maintenance pass: error exit = %d\n", status);
  300.     endkrent();
  301.     maint_release_mem();
  302.     return(status);
  303. }    /* maintenance */
  304.  
  305.  
  306. static struct pubkey *pklist, **pkhash = NULL;
  307.  
  308. #define    PK_HASHSIZE    256        /* must be power of 2 */
  309. #define    PK_HASH(x)        (*(byte *) (x) & (PK_HASHSIZE - 1))
  310.  
  311. /*
  312.  * get the pubkey struct for keyID from hash table, allocate a new
  313.  * node and insert in hash table if necessary.
  314.  */
  315. static struct pubkey *
  316. getpubkey(byte *keyID)
  317. {
  318.     struct pubkey *pk;
  319.     for (pk = pkhash[PK_HASH(keyID)]; pk; pk = pk->pk_hash)
  320.         if (memcmp(pk->pk_keyid, keyID, KEYFRAGSIZE) == 0)
  321.             return pk;
  322.     pk = allocn(sizeof(struct pubkey));
  323.     memset(pk, 0, sizeof(struct pubkey));
  324.     memcpy(pk->pk_keyid, keyID, KEYFRAGSIZE);
  325.     pk->pk_hash = pkhash[PK_HASH(keyID)];
  326.     pkhash[PK_HASH(keyID)] = pk;
  327.     return pk;
  328. }
  329.  
  330. /*
  331.  * Read in keyring, a graph of keys, userids and signatures is built.
  332.  * Also check if axiomatic keys are present in the secret keyring and
  333.  * compare them with the floppy ring if this is requested.
  334.  */
  335. static int
  336. maint_read_data(char *ringfile)
  337. {
  338.     FILE *f;
  339.     int status;
  340.     char userid[256];
  341.     byte keyID[KEYFRAGSIZE];
  342.     byte sigkeyID[KEYFRAGSIZE];
  343.     byte ctb;
  344.     byte keyctrl;
  345.     boolean buckstop = FALSE, show_user = FALSE;
  346.     int buckstopcount = 0;
  347.     long keypos = 0;
  348.     int skip = 0;
  349.     struct pubkey *pk = NULL;
  350.     struct userid *id = NULL;
  351.     struct signature *sig = NULL;
  352.  
  353.     if ((f = fopen(ringfile,FOPRBIN)) == NULL)
  354.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  355.         return(-1);
  356.     }
  357.  
  358.     while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) {
  359.         if (status == -3 || status == -2) {
  360.             fclose(f);
  361.             return(status);
  362.         }
  363.         if (status < 0 || is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) {
  364.             skip = 1;    /* version error or bad key */
  365.             continue;
  366.         }
  367.         if (skip) {
  368.             if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
  369.                 skip = 0;
  370.             else
  371.                 continue;
  372.         }
  373.  
  374.         if (is_ctb_type(ctb, CTB_COMMENT_TYPE) || ctb == CTB_KEYCTRL)
  375.             continue;
  376.  
  377.         if (pk && is_ctb_type(ctb, CTB_SKE_TYPE) && !pk->pk_userids) {
  378.             /* sig. cert before userids can only be compromise cert. */
  379.             pk->pk_owntrust = KC_OWNERTRUST_NEVER;
  380.             continue;
  381.         }
  382.  
  383.         /* other packets should have trust byte */
  384.         if (read_trust(f, &keyctrl) < 0) {
  385.             fclose(f);
  386.             return(ERR_NOTRUST);        /* not a public keyring */
  387.         }
  388.  
  389.         switch (ctb_type(ctb)) {
  390.         case CTB_CERT_PUBKEY_TYPE:
  391.             if (pk)
  392.                 pk = pk->pk_next = getpubkey(keyID);
  393.             else
  394.                 pk = pklist = getpubkey(keyID);
  395.  
  396.             if (pk->pk_next) {
  397.                 fprintf(pgpout, PSTR("Keyring contains duplicate key: %s\n"), keyIDstring(keyID));
  398.                 fclose(f);
  399.                 return -1;
  400.             }
  401.  
  402.             if ((keyctrl & KC_BUCKSTOP)) {
  403.                 if (check_secretkey(f, keypos) == 0) {
  404.                     ++buckstopcount;
  405.                     buckstop = TRUE;
  406.                     if (mverbose)
  407.                         fprintf(pgpout, "* %s",keyIDstring(keyID));
  408.                 } else {    /* not in secret keyring */
  409.                     keyctrl &= ~KC_BUCKSTOP;
  410.                     if (TRUST_LEV(keyctrl) == KC_OWNERTRUST_ULTIMATE)
  411.                         keyctrl = KC_OWNERTRUST_ALWAYS;
  412.                     if (mverbose)
  413.                         fprintf(pgpout, ". %s",keyIDstring(keyID));
  414.                 }
  415.                 show_user = mverbose;
  416.             } else {
  417.                 buckstop = FALSE;
  418.                 show_user = FALSE;
  419.             }
  420.             keyctrl &= ~KC_VISITED;
  421.             pk->pk_owntrust = keyctrl;
  422.             pk->pk_userids = id = NULL;
  423.             break;
  424.         case CTB_USERID_TYPE:
  425.             if (!pk)
  426.                 break;
  427.             if (show_user) {
  428.                 if (pk->pk_userids)        /* more than one user ID */
  429.                     fprintf(pgpout, "        ");
  430.                 fprintf(pgpout, "  %s\n", LOCAL_CHARSET(userid));
  431.             }
  432.             if (id)
  433.                 id = id->uid_next = allocn(sizeof(struct userid));
  434.             else
  435.                 id = pk->pk_userids = allocn(sizeof(struct userid));
  436.  
  437.             if (mverbose)
  438.                 id->uid_userid = store_str(userid);
  439.             keyctrl &= ~KC_LEGIT_MASK;
  440.               if (buckstop)
  441.                   keyctrl |= KC_LEGIT_COMPLETE;
  442.               else
  443.                   keyctrl |= KC_LEGIT_UNKNOWN;
  444.             id->uid_next = NULL;
  445.             id->uid_key = pk;
  446.             id->uid_legit = keyctrl;
  447.             id->uid_signatures = sig = NULL;
  448.             break;
  449.         case CTB_SKE_TYPE:
  450.             if (!pk || !id)
  451.                 break;
  452.             if (sig)
  453.                 sig = sig->sig_next = allocn(sizeof(struct signature));
  454.             else
  455.                 sig = id->uid_signatures = allocn(sizeof(struct signature));
  456.             sig->sig_next = NULL;
  457.             sig->sig_uid = id;
  458.             sig->sig_from = getpubkey(sigkeyID);
  459.             sig->sig_nextfrom = sig->sig_from->pk_signed;
  460.             sig->sig_from->pk_signed = sig;
  461.             sig->sig_trust = keyctrl&KC_SIG_CHECKED;
  462.             break;
  463.         } /* switch ctb_type */
  464.         keypos = ftell(f);
  465.     }
  466.     if (buckstopcount == 0 && mverbose)
  467.         fprintf(pgpout, PSTR("No ultimately-trusted keys.\n"));
  468.     fclose(f);
  469.     return(0);
  470. }
  471.  
  472.  
  473. /*
  474.  * scan keyring for buckstop keys and start the recursive trace_sig_chain()
  475.  * on them
  476.  */
  477. static int
  478. maint_trace_chain(void)
  479. {
  480.     char *userid;
  481.     struct pubkey *pk;
  482.  
  483.     for (pk = pklist; pk; pk = pk->pk_next) {
  484.         if (!(pk->pk_owntrust&KC_BUCKSTOP))
  485.             continue;
  486.         if (mverbose)
  487.             fprintf(pgpout, "* %s\n", LOCAL_CHARSET(pk->pk_userids->uid_userid));
  488.         if (TRUST_LEV(pk->pk_owntrust) == KC_OWNERTRUST_UNDEFINED) {
  489.             userid = user_from_keyID(pk->pk_keyid);
  490.             SET_TRUST(&pk->pk_owntrust, ask_owntrust(userid, pk->pk_owntrust));
  491.         }
  492.         trace_sig_chain(pk, 0);
  493.     }
  494.     return 0;
  495. }
  496.  
  497.  
  498. /*
  499.  * Find all signatures made with the key pk.
  500.  * If a trusted signature makes a key fully legit then signatures made
  501.  * with this key are also recursively traced on down the tree.
  502.  *
  503.  * depth is the level of recursion, it is used to indent the userIDs
  504.  * and to check if we don't exceed the limit "max_cert_depth"
  505.  *
  506.  * NOTE: a signature made with a key with pk_depth == max_cert_depth will
  507.  * not be counted here to limit the maximum chain length, but will be
  508.  * counted when the validity of a key is computed in maint_final()
  509.  */
  510. static int
  511. trace_sig_chain(struct pubkey *pk, int depth)
  512. {
  513.     int d, trust_count = 0;
  514.     int counts[MAX_DEPTH];
  515.     struct signature *sig, *s;
  516.     struct pubkey *p;
  517.     struct userid *id;
  518.  
  519.     assert(depth <= max_cert_depth);
  520.     if (pk->pk_depth && pk->pk_depth <= depth)
  521.         return 0;
  522.     pk->pk_depth = depth;
  523.  
  524.     /* Should we ask for trust.  If this key is legit, then go for
  525.      * it!  Ask the user....
  526.      */    
  527.     if (TRUST_LEV(pk->pk_owntrust) == KC_OWNERTRUST_UNDEFINED)
  528.         for (id = pk->pk_userids; id; id = id->uid_next) {
  529.             compute_legit(id);
  530.             if ((id->uid_legit & KC_LEGIT_MASK) == 
  531.                 KC_LEGIT_COMPLETE) {
  532.                 SET_TRUST(&pk->pk_owntrust,
  533.                       ask_owntrust(user_from_keyID(pk->pk_keyid), 
  534.                                pk->pk_owntrust));
  535.                 break;
  536.             }
  537.         }
  538.  
  539.     /* Return if I haven't signed anyone's keys, since I
  540.      * don't need to check any further..  -warlord 93-04-11
  541.      */
  542.     if (!pk->pk_signed)
  543.         return 0;
  544.  
  545. #ifdef DEBUG
  546.     if (mverbose)
  547.         fprintf(pgpout, "%*s%d-v  %s\n", 2*depth, "", depth, pk->pk_userids->uid_userid);
  548. #endif
  549.  
  550.     /* all keys signed by pk */
  551.     for (sig = pk->pk_signed; sig; sig = sig->sig_nextfrom) {
  552.         if (mverbose)
  553.             fprintf(pgpout, "%*s  > %s\n", 2*depth, "", LOCAL_CHARSET(sig->sig_uid->uid_userid));
  554.  
  555.         /* copy trust from signator */
  556.         SET_TRUST(&sig->sig_trust, TRUST_LEV(pk->pk_owntrust));
  557.         sig->sig_trust |= KC_CONTIG;    /* CONTIG bit currently unused */
  558.  
  559.         p = sig->sig_uid->uid_key;    /* this key signed by pk */
  560.         if (p->pk_owntrust & KC_BUCKSTOP)
  561.             continue;    /* will be handled from main loop */
  562.         if (p->pk_depth && p->pk_depth <= depth+1)
  563.             continue;    /* already handled this key at a lower level */
  564.  
  565.         for (d = 0; d < max_cert_depth; ++d)
  566.             counts[d] = 0;
  567.         for (s = sig->sig_uid->uid_signatures; s; s = s->sig_next) {
  568.             d = s->sig_from->pk_depth;
  569.             if (d < max_cert_depth)
  570.                 counts[d] += TRUST_FAC(s->sig_trust);
  571.         }
  572.         /*
  573.          * find a combination of signatures that will make the key
  574.          * valid through the shortest cert. path.
  575.          */
  576.         trust_count = 0;
  577.         for (d = 0; d < max_cert_depth; ++d) {
  578.             trust_count += counts[d];
  579.             if (trust_count >= complete_min) {
  580.                 trace_sig_chain(p, d+1);
  581.                 break;
  582.             }
  583.         }
  584.     }
  585.  
  586. #ifdef DEBUG
  587.     if (mverbose)
  588.         fprintf(pgpout, "%*s%d-^  %s\n", 2*depth, "", depth, pk->pk_userids->uid_userid);
  589. #endif
  590.     return 0;
  591. }
  592.  
  593. /*
  594.  * compute validity of userid/key pair, the number of signatures and the
  595.  * trust level of these signatures determines the validity.
  596.  */
  597. static void
  598. compute_legit(struct userid *id)
  599. {
  600.     struct signature *s;
  601.     int trust_count, legit;
  602.  
  603.     if (id->uid_key->pk_owntrust & KC_BUCKSTOP)
  604.         legit = KC_LEGIT_COMPLETE;
  605.     else {
  606.         trust_count = 0;
  607.         for (s = id->uid_signatures; s; s = s->sig_next)
  608.             trust_count += TRUST_FAC(s->sig_trust);
  609.  
  610.         if (trust_count == 0)
  611.             legit = KC_LEGIT_UNKNOWN;
  612.         else if (trust_count < marginal_min)
  613.             legit = KC_LEGIT_UNTRUSTED;
  614.         else if (trust_count < complete_min)
  615.             legit = KC_LEGIT_MARGINAL;
  616.         else
  617.             legit = KC_LEGIT_COMPLETE;
  618.     }
  619.     id->uid_legit = (id->uid_legit & ~KC_LEGIT_MASK) | legit;
  620. }
  621.  
  622. /* 
  623.  * check if the maintenance pass changed anything
  624.  * returns 0 if files f and g are equal and the number of changed
  625.  * trust bytes if the files are different or a negative value on error
  626.  */
  627. static int
  628. maint_final(char *ringfile)
  629. {
  630.     int status;
  631.     FILE *f;
  632.     long trust_pos = 0;
  633.     char userid[256];
  634.     byte keyID[KEYFRAGSIZE];
  635.     byte sigkeyID[KEYFRAGSIZE];
  636.     byte ctb;
  637.     byte kc_orig, kc_new = 0, mask;
  638.     int changed = 0;
  639.     int skip = 0;
  640.     struct pubkey *pk;
  641.     struct userid *id = NULL;
  642.     struct signature *sig = NULL;
  643.  
  644.     if (check_only)
  645.         f = fopen(ringfile,FOPRBIN);
  646.     else
  647.         f = fopen(ringfile,FOPRWBIN);
  648.     if (f == NULL)
  649.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  650.         return(-1);
  651.     }
  652.  
  653.     pk = pklist;
  654.     while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) {
  655.         if (status == -3 || status == -2)
  656.             break;
  657.         if (status < 0 || is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) {
  658.             skip = 1;
  659.             continue;
  660.         }
  661.         if (skip) {
  662.             if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
  663.                 skip = 0;
  664.             else
  665.                 continue;
  666.         }
  667.         if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE) || 
  668.                 is_ctb_type(ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) {
  669.             trust_pos = ftell(f);
  670.             if (read_trust(f, &kc_orig) < 0) {
  671.                 status = ERR_NOTRUST;
  672.                 if (is_ctb_type(ctb, CTB_SKE_TYPE))
  673.                     continue;    /* skip compr. cert. */
  674.                 else
  675.                     break;
  676.             }
  677.         }
  678.         switch (ctb_type(ctb)) {
  679.             case CTB_CERT_PUBKEY_TYPE:
  680.                 assert(pk && !memcmp(pk->pk_keyid, keyID, KEYFRAGSIZE));
  681.                 assert(!sig && !id);
  682.                 id = pk->pk_userids;
  683.                 kc_new = pk->pk_owntrust;
  684. #ifdef DEBUG
  685.                 if (mverbose)
  686.                     fprintf(pgpout, "  ------ %d\n", pk->pk_depth);
  687. #endif
  688.                 pk = pk->pk_next;
  689.                 mask = KC_OWNERTRUST_MASK|KC_BUCKSTOP;
  690.                 break;
  691.             case CTB_USERID_TYPE:
  692.                 assert(id && !sig);
  693.                 sig = id->uid_signatures;
  694.                 compute_legit(id);
  695.                 kc_new = id->uid_legit;
  696. #ifdef DEBUG
  697.                 if (mverbose)
  698.                     fprintf(pgpout, "%c %02x  %02x  %s\n", ' ' + (kc_new != kc_orig),
  699.                         kc_orig, kc_new, id->uid_userid);
  700. #endif
  701.                 id = id->uid_next;
  702.                 mask = KC_LEGIT_MASK;
  703.                 break;
  704.             case CTB_SKE_TYPE:
  705.                                 assert(sig != NULL);
  706.                 assert(!memcmp(sig->sig_from->pk_keyid, sigkeyID, KEYFRAGSIZE));
  707.                 kc_new = sig->sig_trust;
  708. #ifdef DEBUG
  709.                 if (mverbose && sig->sig_from->pk_userids)
  710.                     fprintf(pgpout, "%c %02x  %02x    %s\n", ' ' + (kc_new != kc_orig),
  711.                         kc_orig, kc_new, sig->sig_from->pk_userids->uid_userid);
  712. #endif
  713.                 sig = sig->sig_next;
  714.                 mask = KC_SIGTRUST_MASK|KC_CONTIG;
  715.                 break;
  716.             default:
  717.                 mask = 0;
  718.         }
  719.         if ((kc_new&mask) != (kc_orig&mask)) {
  720.             if (!check_only)
  721.                 write_trust_pos(f, kc_new, trust_pos);
  722.             ++changed;
  723.         }
  724.     }
  725.     fclose(f);
  726.     if (status < -1)    /* -1 is OK, EOF */
  727.         return(status);
  728.     if (pk || sig || id) {
  729.         fprintf(pgpout, "maint_final: internal error\n");
  730.         return -1;
  731.     }
  732.     return(changed);
  733. }    /* maint_final */
  734.  
  735.  
  736. int
  737. maint_list(char *ringfile)
  738. {
  739.     int status;
  740.     FILE *f;
  741.     char userid[256];
  742.     byte keyID[KEYFRAGSIZE];
  743.     byte sigkeyID[KEYFRAGSIZE];
  744.     char *signator;
  745.     char tchar = 0;
  746.     byte ctb, kc;
  747.     int owntrust = 0;
  748.     int usercount = 0;
  749.  
  750.     if ((f = fopen(ringfile,FOPRBIN)) == NULL)
  751.     {    fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),ringfile);
  752.         return(-1);
  753.     }
  754.     init_trust_lst();
  755.     setkrent(ringfile);
  756.     init_userhash();
  757.  
  758. #ifdef PGP26_COMPAT
  759.       fprintf(pgpout, PSTR("  KeyID     Trust      Validity  User ID\n"));
  760. #else
  761.     fprintf(pgpout, PSTR("  KeyID   Trust      Validity  User ID\n"));
  762. #endif
  763.     while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) {
  764.         if (status == -3 || status == -2)
  765.             break;
  766.         if (status < 0)
  767.             continue;
  768.  
  769.         if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE) || 
  770.                 is_ctb_type(ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) {
  771.             if (read_trust(f, &kc) < 0) {
  772.                 status = ERR_NOTRUST;
  773.                 /* compromise cert. don't have trust byte */
  774.                 if (!is_ctb_type(ctb, CTB_SKE_TYPE))
  775.                     break;
  776.             }
  777.         }
  778.  
  779.         switch (ctb_type(ctb)) {
  780.         case CTB_CERT_PUBKEY_TYPE:
  781.             tchar = (kc & KC_BUCKSTOP ? '*' : ' ');
  782.             owntrust = TRUST_LEV(kc);
  783.             usercount = 0;
  784.             userid[0] = '\0';
  785.             break;
  786.         case CTB_USERID_TYPE:
  787.             if (!usercount) {    /* first userid */
  788.                 fprintf(pgpout, "%c %s ", tchar, keyIDstring(keyID));
  789.                 fprintf(pgpout, " %-*s", trustlst_len, trust_lst[owntrust]);
  790.             } else
  791. #ifdef PGP26_COMPAT
  792.                               fprintf(pgpout, "           %*s ", trustlst_len, "");
  793. #else
  794.                 fprintf(pgpout, "         %*s ", trustlst_len, "");
  795. #endif
  796.             fprintf(pgpout, " %-*s", legitlst_len, legit_lst[kc&KC_LEGIT_MASK]);
  797.             if (usercount)
  798.                 putc(' ', pgpout);
  799.               ++usercount;
  800.             fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid));
  801.             break;
  802.         case CTB_SKE_TYPE:
  803.             if (!usercount) {    /* sig before userid: compromise cert. */
  804.                 tchar = '#';
  805.                 break;
  806.             }
  807. #ifdef PGP26_COMPAT
  808.                       fprintf(pgpout, "%c          ", (kc & KC_CONTIG) ? 'c' : ' ');
  809. #else
  810.             fprintf(pgpout, "%c        ", (kc & KC_CONTIG) ? 'c' : ' ');
  811. #endif
  812.             fprintf(pgpout, " %-*s", trustlst_len, trust_lst[TRUST_LEV(kc)]);
  813. #ifdef PGP26_COMPAT
  814.                       fprintf(pgpout, "%*s  ", legitlst_len, "");
  815. #else
  816.             fprintf(pgpout, "%*s   ", legitlst_len, "");
  817. #endif
  818.             if ((signator = user_from_keyID(sigkeyID)) == NULL)
  819.                 fprintf(pgpout, "(KeyID: %s)\n",keyIDstring(sigkeyID));
  820.             else
  821.                 fprintf(pgpout, "%s\n", LOCAL_CHARSET(signator));
  822.             break;
  823.         }
  824.     }
  825.     endkrent();
  826.     fclose(f);
  827.     if (status < -1)    /* -1 is OK, EOF */
  828.         return(status);
  829.     return(0);
  830. }    /* maint_list */
  831.  
  832.  
  833. /*
  834.  * translate the messages in the arrays trust_lst and legit_lst.
  835.  * trustlst_len and legitlst_len will be set to the length of
  836.  * the longest translated string.
  837.  */
  838. void
  839. init_trust_lst(void)
  840. {
  841.     static int initialized = 0;
  842.     int i, len;
  843.     char *s;
  844.  
  845.     if (initialized)
  846.         return;
  847.     for (i = 0; i < 8; ++i)
  848.     {    if (trust_lst[i][0])
  849.         {    s = PSTR (trust_lst[i]);
  850.             if (s != trust_lst[i])
  851.                 strncpy(trust_lst[i], s, sizeof(trust_lst[0]) - 1);
  852.             len = strlen(s);
  853.             if (len > trustlst_len)
  854.                 trustlst_len = len;
  855.         }
  856.     }
  857.     for (i = 0; i < 4; ++i)
  858.     {    s = PSTR (legit_lst[i]);
  859.         if (s != legit_lst[i])
  860.             strncpy(legit_lst[i], s, sizeof(legit_lst[0]) - 1);
  861.         len = strlen(s);
  862.         if (len > legitlst_len)
  863.             legitlst_len = len;
  864.     }
  865.     ++trustlst_len;
  866.     ++legitlst_len;
  867.     initialized = 1;
  868. }    /* init_trust_lst */
  869.  
  870.  
  871.  
  872. /*
  873.  * compare the key in file f at keypos with the matching key in the
  874.  * secret keyring, the global variable sec_fp must contain the file pointer
  875.  * for of the secret keyring.
  876.  *
  877.  * returns 1 if the key was not found, -2 if the keys were different
  878.  * and 0 if the keys compared OK
  879.  */
  880. static int
  881. check_secretkey(FILE *f, long keypos)
  882. {
  883.     int status = -1;
  884.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  885.     unit nsec[MAX_UNIT_PRECISION], esec[MAX_UNIT_PRECISION];
  886.     char userid[256];
  887.     byte keyID[KEYFRAGSIZE];
  888.     long savepos, pktlen;
  889.     byte ctb;
  890.  
  891.     if (sec_fp == NULL)
  892.         return(-1);
  893.  
  894.     savepos = ftell(f);
  895.     fseek(f, keypos, SEEK_SET);
  896.     if (readkeypacket(f, FALSE, &ctb, NULL, NULL, n, e,
  897.                     NULL, NULL, NULL, NULL, NULL, NULL) < 0)
  898.         goto ex;
  899.     extract_keyID(keyID, n);
  900.  
  901.     do    /* get userid */
  902.     {    status = readkpacket(f, &ctb, userid, NULL, NULL);
  903.         if (status == -1 || status == -3)
  904.             goto ex;
  905.     } while (ctb != CTB_USERID);
  906.  
  907.     if (lookup_by_keyID(sec_fp, keyID) < 0)
  908.     {
  909. #if 0
  910.         if (!check_only)
  911.         {
  912.             fprintf(pgpout, PSTR (
  913. "\nAn \"axiomatic\" key is one which does not need certifying by\n\
  914. anyone else.  Usually this special status is reserved only for your\n\
  915. own keys, which should also appear on your secret keyring.  The owner\n\
  916. of an axiomatic key (who is typically yourself) is \"ultimately trusted\"\n\
  917. by you to certify any or all other keys.\n"));
  918.             fprintf(pgpout, PSTR ("\nKey for user ID: \"%s\"\n\
  919. is designated as an \"ultimately-trusted\" introducer, but the key\n\
  920. does not appear in the secret keyring.\n\
  921. Use this key as an ultimately-trusted introducer (y/N)? "), 
  922.                 LOCAL_CHARSET(userid));
  923.             status = (getyesno('n') ? 0 : 1);
  924.         }
  925. #else
  926.         status = 1;
  927. #endif
  928.     }
  929.     else
  930.     {
  931.         long kpos = ftell(sec_fp);
  932.         if (readkeypacket(sec_fp, FALSE, &ctb, NULL, NULL, nsec, esec,
  933.                         NULL, NULL, NULL, NULL, NULL, NULL) < 0)
  934.         {
  935.             fprintf(pgpout, PSTR("\n\007Cannot read from secret keyring.\n"));
  936.             status = -3;
  937.             goto ex;
  938.         }
  939.         if (mp_compare(n, nsec) || mp_compare(e, esec))
  940.         {    /* Red Alert! */
  941.             fprintf(pgpout, PSTR("\n\007WARNING: Public key for user ID: \"%s\"\n\
  942. does not match the corresponding key in the secret keyring.\n"), 
  943.                 LOCAL_CHARSET(userid));
  944.             fprintf(pgpout, PSTR("This is a serious condition, indicating possible keyring tampering.\n"));
  945.             status = -2;
  946.         }
  947.         else
  948.             status = 0;
  949.  
  950.         if (floppy_fp)
  951.         {
  952.             if (lookup_by_keyID(floppy_fp, keyID) < 0)
  953.             {
  954.                 fprintf(pgpout, PSTR("Public key for: \"%s\"\n\
  955. is not present in the backup keyring '%s'.\n"),
  956.                     LOCAL_CHARSET(userid), floppyring);
  957.             }
  958.             else
  959.             {
  960.                 pktlen = ftell(sec_fp) - kpos;
  961.                 fseek(sec_fp, kpos, SEEK_SET);
  962.                 while (--pktlen >= 0 && getc(sec_fp) == getc(floppy_fp)) ;
  963.                 if (pktlen != -1)
  964.                 {
  965.                     fprintf(pgpout, PSTR("\n\007WARNING: Secret key for: \"%s\"\n\
  966. does not match the key in the backup keyring '%s'.\n"),
  967.                         LOCAL_CHARSET(userid), floppyring);
  968.                     fprintf(pgpout, PSTR("This is a serious condition, indicating possible keyring tampering.\n"));
  969.                     status = -2;
  970.                 }
  971.             }
  972.         }
  973.     }
  974. ex:
  975.     fseek(f, savepos, SEEK_SET);
  976.     return(status);
  977. }    /* check_secretkey */
  978.  
  979.  
  980. /*
  981.  * setup tables for trust scoring.
  982.  */
  983. static void
  984. setup_trust(void)
  985. {    /* initialize trust table */
  986.     if (marg_min == 0)    /* marginally trusted signatures are ignored */
  987.     {
  988.         trust_tbl[5] = 0;
  989.         trust_tbl[6] = 1;
  990.         complete_min = compl_min;
  991.     }
  992.     else
  993.     {
  994.         if (marg_min < compl_min)
  995.             marg_min = compl_min;
  996.         trust_tbl[5] = compl_min;
  997.         trust_tbl[6] = marg_min;
  998.         complete_min = compl_min * marg_min;
  999.     }
  1000.     trust_tbl[7] = complete_min;    /* ultimate trust */
  1001.     marginal_min = complete_min / 2;
  1002. }    /* setup_trust */
  1003.  
  1004.  
  1005. int ask_owntrust(char *userid, byte cur_trust)
  1006. /* Ask for a wetware decision from the human on how much to trust 
  1007. this key's owner to certify other keys.  Returns trust value. */
  1008. {
  1009.     char buf[8];
  1010.  
  1011.     if (check_only || filter_mode || batchmode)
  1012.     {    /* not interactive */
  1013.         ++undefined_trust;    /* We complete/undefined. Why?  */
  1014.         return(KC_OWNERTRUST_UNDEFINED);
  1015.     }
  1016.  
  1017.     fprintf(pgpout, 
  1018. PSTR("\nMake a determination in your own mind whether this key actually\n\
  1019. belongs to the person whom you think it belongs to, based on available\n\
  1020. evidence.  If you think it does, then based on your estimate of\n\
  1021. that person's integrity and competence in key management, answer\n\
  1022. the following question:\n"));  
  1023.     fprintf(pgpout, PSTR("\nWould you trust \"%s\"\n\
  1024. to act as an introducer and certify other people's public keys to you?\n\
  1025. (1=I don't know. 2=No. 3=Usually. 4=Yes, always.) ? "), 
  1026.         LOCAL_CHARSET(userid));
  1027.     fflush(pgpout);
  1028.     getstring(buf, sizeof(buf)-1, TRUE);
  1029.     switch (buf[0])
  1030.     {    case '1': return KC_OWNERTRUST_UNKNOWN;
  1031.         case '2': return KC_OWNERTRUST_NEVER;
  1032.         case '3': return KC_OWNERTRUST_USUALLY;
  1033.         case '4': return KC_OWNERTRUST_ALWAYS;
  1034.         default: return(TRUST_LEV(cur_trust));
  1035.     }
  1036. }    /* ask_owntrust */
  1037.  
  1038.  
  1039. /*
  1040.  * scan keyfile f for keyID srch_keyID.
  1041.  * returns the file position of the key if it is found, and sets the
  1042.  * file pointer to the start of the key packet.
  1043.  * returns -1 if the key was not found or < -1 if there was an error
  1044.  */
  1045. long
  1046. lookup_by_keyID(FILE *f, byte *srch_keyID)
  1047. {
  1048.     int status;
  1049.     long keypos = 0;
  1050.     byte keyID[KEYFRAGSIZE];
  1051.     byte ctb;
  1052.  
  1053.     rewind(f);
  1054.     while ((status = readkpacket(f, &ctb, NULL, keyID, NULL)) != -1)
  1055.     {
  1056.         if (status == -3 || status == -2)
  1057.             break;
  1058.         if (status < 0)
  1059.             continue;
  1060.         if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0)
  1061.         {
  1062.             fseek(f, keypos, SEEK_SET);
  1063.             return(keypos);
  1064.         }
  1065.         keypos = ftell(f);
  1066.     }
  1067.     return(status);
  1068. }    /* lookup_by_keyID */
  1069.  
  1070. /*
  1071.  * look up the key matching "keyID" and print the first userID
  1072.  * of this key.  File position of f is saved.
  1073.  */
  1074. void
  1075. show_userid(FILE *f, byte *keyID)
  1076. {
  1077.     int status;
  1078.     long filepos;
  1079.     char userid[256];
  1080.     byte ctb;
  1081.  
  1082.     filepos = ftell(f);
  1083.     if (lookup_by_keyID(f, keyID) >= 0)
  1084.         while ((status = readkpacket(f, &ctb, userid, NULL, NULL)) != -1 && status != -3)
  1085.             if (ctb == CTB_USERID)
  1086.             {
  1087.                 fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid));
  1088.                 fseek(f, filepos, SEEK_SET);
  1089.                 return;
  1090.             }
  1091.  
  1092.     fprintf(pgpout, "(KeyID: %s)\n",keyIDstring(keyID));
  1093.     fseek(f, filepos, SEEK_SET);
  1094. }    /* show_userid */
  1095.  
  1096.  
  1097. /*
  1098.  * messages printed by show_key()
  1099.  */
  1100. static char *owntrust_msg[] = {
  1101.     "", /* Just don't say anything in this case */
  1102.     "",
  1103.     _PSTR("This user is untrusted to certify other keys.\n"),
  1104.     "", /* reserved */
  1105.     "", /* reserved */
  1106.     _PSTR("This user is generally trusted to certify other keys.\n"),
  1107.     _PSTR("This user is completely trusted to certify other keys.\n"),
  1108.     _PSTR("This axiomatic key is ultimately trusted to certify other keys.\n"),
  1109. };
  1110. static char *keylegit_msg[] = {
  1111.     _PSTR("This key/userID association is not certified.\n"),
  1112.     _PSTR("This key/userID association is not certified.\n"),
  1113.     _PSTR("This key/userID association is marginally certified.\n"),
  1114.     _PSTR("This key/userID association is fully certified.\n"),
  1115. };
  1116. static char *sigtrust_msg[] = {
  1117.     _PSTR("  Questionable certification from:\n  "),
  1118.     _PSTR("  Questionable certification from:\n  "),
  1119.     _PSTR("  Untrusted certification from:\n  "),
  1120.     "", /* reserved */
  1121.     "", /* reserved */
  1122.     _PSTR("  Generally trusted certification from:\n  "),
  1123.     _PSTR("  Completely trusted certification from:\n  "),
  1124.     _PSTR("  Axiomatically trusted certification from:\n  "),
  1125. };
  1126.  
  1127. /*
  1128.  * show the key in file f at file position keypos.
  1129.  * 'what' controls the info that will be shown:
  1130.  *   SHOW_TRUST: show trust byte info
  1131.  *   SHOW_SIGS:  show signatures
  1132.  *   SHOW_HASH:  show key fingerprint
  1133.  * these constants can be or'ed
  1134.  *
  1135.  * 'what' can also be SHOW_LISTFMT to get the same format as for pgp -kv
  1136.  * no signatures or extra userids will be printed in this case.
  1137.  *
  1138.  * 'what' can be SHOW_CHANGE, in which case it will take the keyID and
  1139.  * call show_update();
  1140.  */
  1141. int
  1142. show_key(FILE *f, long keypos, int what)
  1143. {
  1144.     int status, keystatus = -1;
  1145.     long filepos;
  1146.     char userid[256];
  1147.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1148.     byte sigkeyID[KEYFRAGSIZE];
  1149.     word32 timestamp;
  1150.     byte ctb, keyctb = 0, keyctrl;
  1151.     int userids = 0;
  1152.     boolean print_trust = FALSE;
  1153.     byte hash[16];
  1154.     int precision = global_precision;
  1155.     int compromised = 0;
  1156.     int disabled = 0;
  1157.  
  1158.     filepos = ftell(f);
  1159.     fseek(f, keypos, SEEK_SET);
  1160.     while ((status = readkeypacket(f, FALSE, &ctb, (byte *)×tamp, userid,
  1161.                     n, e, NULL, NULL, NULL, NULL, sigkeyID, &keyctrl)) != -1)
  1162.     {
  1163.         if (status == -2 || status == -3)
  1164.             break;
  1165.         if (is_key_ctb(ctb))
  1166.         {    if (userids)
  1167.                 break;
  1168.             if (what & SHOW_HASH)
  1169.                 getKeyHash(hash, n, e);
  1170.             keyctb = ctb;
  1171.             keystatus = status;    /* remember status, could be version error */
  1172.         }
  1173.         else if (ctb == CTB_KEYCTRL)  /* trust bytes only in public keyrings */
  1174.         {
  1175.             if (keystatus >= 0 && !userids)    /* key packet trust byte */
  1176.                 if (keyctrl & KC_DISABLED)
  1177.                     disabled = 1;
  1178.             if (what & SHOW_TRUST)
  1179.                 print_trust = TRUE;
  1180.         }
  1181.         else if (ctb == CTB_USERID)
  1182.         {    if (userids == 0)
  1183.             {    PascalToC(userid);    /* for display */
  1184.                 ++userids;
  1185.                 if (what & SHOW_CHANGE) {
  1186.                     show_update(key2IDstring(n));
  1187.                     break;
  1188.                 }
  1189.                 if (what & SHOW_LISTFMT) {
  1190.                     if (is_ctb_type(keyctb,CTB_CERT_PUBKEY_TYPE))
  1191.                         fprintf(pgpout,"pub");
  1192.                     else if (is_ctb_type(keyctb,CTB_CERT_SECKEY_TYPE))
  1193.                         fprintf(pgpout,"sec");
  1194.                     else
  1195.                         fprintf(pgpout,"???");
  1196.                     if (keystatus < 0)
  1197.                         fprintf(pgpout,"? ");
  1198.                     else if (compromised)
  1199.                         fprintf(pgpout,"# ");
  1200.                     else if (disabled)
  1201.                         fprintf(pgpout,"- ");
  1202.                     else
  1203.                         fprintf(pgpout,"  ");
  1204. #ifdef PGP26_COMPAT
  1205.                                       fprintf(pgpout,"%4d/%s %s ",
  1206. #else
  1207.                     fprintf(pgpout,"%4d/%s %s  ",
  1208. #endif
  1209.                         countbits(n),key2IDstring(n),cdate(×tamp));
  1210.                     fprintf(pgpout,"%s\n",LOCAL_CHARSET(userid));
  1211.                     break;    /* only print default userid */
  1212.                 }
  1213.                 fprintf(pgpout,PSTR("\nKey for user ID: %s\n"),
  1214.                     LOCAL_CHARSET(userid));
  1215.                 fprintf(pgpout,PSTR("%d-bit key, Key ID %s, created %s\n"),
  1216.                     countbits(n), key2IDstring(n), cdate(×tamp) );
  1217.                 if (keystatus == -4)
  1218.                     fprintf(pgpout,PSTR("Bad key format.\n"));
  1219.                 else if (keystatus == -6)
  1220.                     fprintf(pgpout,PSTR("Unrecognized version.\n"));
  1221.                 else if (what & SHOW_HASH)
  1222.                     printKeyHash(hash, FALSE);
  1223.                 if (compromised)
  1224.                     fprintf(pgpout, PSTR("Key has been revoked.\n"));
  1225.                 if (disabled)
  1226.                     fprintf(pgpout, PSTR("Key is disabled.\n"));
  1227.                 if (print_trust && *owntrust_msg[TRUST_LEV(keyctrl)] != '\0')
  1228.                     fprintf(pgpout, PSTR (owntrust_msg[TRUST_LEV(keyctrl)]));
  1229.             }
  1230.             else
  1231.             {    PascalToC(userid);
  1232.                 if (what != 0)
  1233.                     fprintf(pgpout, "\n");
  1234.                 fprintf(pgpout,PSTR("Also known as: %s\n"), 
  1235.                     LOCAL_CHARSET(userid));
  1236.             }
  1237.             if (print_trust) {
  1238.                 read_trust(f, &keyctrl);
  1239.                 fprintf(pgpout, PSTR (keylegit_msg[keyctrl&KC_LEGIT_MASK]));
  1240.             }    /* print_trust */
  1241.         }
  1242.         else if (is_ctb_type(ctb, CTB_SKE_TYPE))
  1243.         {
  1244.             if (userids == 0)
  1245.                 compromised = 1;
  1246.             if (what & SHOW_CHANGE) {
  1247.                 show_update(key2IDstring(n));
  1248.                 break;
  1249.             }
  1250.             if (what & SHOW_SIGS) {
  1251.                 if (print_trust) {
  1252.                     read_trust(f, &keyctrl);
  1253.                     fprintf(pgpout, PSTR (sigtrust_msg[TRUST_LEV(keyctrl)]));
  1254.                 }
  1255.                 else
  1256.                     fprintf(pgpout, PSTR("  Certified by: "));
  1257.                 show_userid(f, sigkeyID);
  1258.             }
  1259.         }
  1260.     }
  1261.     if (status == -1 && userids)
  1262.         status = 0;
  1263.     set_precision(precision);
  1264.     fseek(f, filepos, SEEK_SET);
  1265.     return(status);
  1266. }    /* show_key */
  1267.  
  1268. /* show_update -- this function just prints an update message to
  1269.  * pgpout to inform the user that an update happened.
  1270.  */
  1271. void
  1272. show_update(char *s)
  1273. {
  1274.     fprintf(pgpout, "Updated keyID: 0x%s\n", s);
  1275. }
  1276.  
  1277.  
  1278. /*
  1279.  * stripped down version of readkeypacket(), the output userid
  1280.  * is a null terminated string.
  1281.  */
  1282. int
  1283. readkpacket(FILE *f, byte *ctb, char *userid, byte *keyID, byte *sigkeyID)
  1284. {
  1285.     int status;
  1286.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  1287.  
  1288.     status = readkeypacket(f, FALSE, ctb, NULL, userid, n, e,
  1289.                     NULL, NULL, NULL, NULL, sigkeyID, NULL);
  1290.  
  1291.     if (status < 0)
  1292.     {
  1293. #ifdef DEBUG
  1294.         if (status < -1)
  1295.             fprintf(stderr, "readkeypacket returned %d\n", status);
  1296. #endif
  1297.         return(status);
  1298.     }
  1299.  
  1300.     if (keyID && is_key_ctb(*ctb))
  1301.         extract_keyID(keyID, n);
  1302.  
  1303.     if (userid && *ctb == CTB_USERID)
  1304.         PascalToC(userid);
  1305.  
  1306.     return(0);
  1307. }    /* readkpacket */
  1308.  
  1309.  
  1310. /*
  1311.  * write trust byte "keyctrl" to file f at file position "pos"
  1312.  */
  1313. void
  1314. write_trust_pos(FILE *f, byte keyctrl, long pos)
  1315. {
  1316.     long fpos;
  1317.  
  1318.     fpos = ftell(f);
  1319.     fseek(f, pos, SEEK_SET);
  1320.     write_trust(f, keyctrl);
  1321.     fseek(f, fpos, SEEK_SET);
  1322. }    /* write_trust_pos */
  1323.  
  1324.  
  1325. /*
  1326.  * read a trust byte packet from file f, the trust byte will be
  1327.  * stored in "keyctrl".
  1328.  * returns -1 on EOF, -3 on corrupt input, and ERR_NOTRUST if
  1329.  * the packet was not a trust byte (this can be used to check if
  1330.  * a file is a keyring (with trust bytes) or a keyfile).
  1331.  * The current file position is left unchanged in this case.
  1332.  */
  1333. int
  1334. read_trust(FILE *f, byte *keyctrl)
  1335. {
  1336.     unsigned char buf[3];
  1337.  
  1338.     if (fread(buf, 1, 3, f) != 3)
  1339.         return -1;
  1340.     if (buf[0] != CTB_KEYCTRL) {
  1341.         if (is_ctb(buf[0])) {
  1342.             fseek(f, -3L, SEEK_CUR);
  1343.             return(ERR_NOTRUST);
  1344.         } else
  1345.             return(-3);        /* bad data */
  1346.     }
  1347.     if (buf[1] != 1)        /* length must be 1 */
  1348.         return(-3);
  1349.     if (keyctrl)
  1350.         *keyctrl = buf[2];
  1351.     return(0);
  1352. }    /* read_trust */
  1353.  
  1354.  
  1355.  
  1356. /****** userid lookup ******/
  1357.  
  1358. #define    HASH_ALLOC    (ALLOC_UNIT / sizeof(struct hashent))
  1359.  
  1360. static char * store_str(char *str);
  1361. static VOID * allocbuf(int size);
  1362. static void freebufpool();
  1363.  
  1364. static struct hashent {
  1365.     struct hashent *next;
  1366.     byte keyID[KEYFRAGSIZE];
  1367.     char *userid;
  1368. } **hashtbl = NULL, *hashptr;
  1369.  
  1370. static char *strptr;
  1371. static int strleft = 0;
  1372. static int hashleft = 0;
  1373. static int nleft = 0;
  1374.  
  1375. #define MAXKR    8    /* max. number of keyrings for user_from_keyID() */
  1376. static char *krnames[MAXKR];
  1377. static int nkr = 0;
  1378. /*
  1379.  * Lookup userid by keyID without using the in-memory hash table.
  1380.  */
  1381. static char *
  1382. _user_from_keyID(byte *srch_keyID)
  1383. {
  1384.     FILE *f;
  1385.     int i, status, found = 0;
  1386.     byte keyID[KEYFRAGSIZE];
  1387.     static char userid[256];
  1388.     byte ctb;
  1389.  
  1390.     /* search all keyfiles set with setkrent() */
  1391.     for (i = 0; !found && i < nkr; ++i) {
  1392.         if ((f = fopen(krnames[i], FOPRBIN)) == NULL)
  1393.             continue;
  1394.         while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) {
  1395.             if (status == -2 || status == -3)
  1396.                 break;
  1397.             if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0)
  1398.                 found = 1;
  1399.             if (found && ctb == CTB_USERID)
  1400.                 break;
  1401.         }
  1402.         fclose(f);
  1403.     }
  1404.     return(found ? userid : NULL);
  1405. }
  1406.  
  1407. /*
  1408.  * Lookup userid by keyID, use hash table if initialized.
  1409.  */
  1410. char *
  1411. user_from_keyID(byte *keyID)
  1412. {
  1413.     struct hashent *p;
  1414.  
  1415.     if (!hashtbl)
  1416.         return _user_from_keyID(keyID);
  1417.     for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next)
  1418.         if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0)
  1419.             return p->userid;
  1420.     return NULL;
  1421. }
  1422.  
  1423. /*
  1424.  * add keyfile to userid hash table, userids are added, endkrent() clears
  1425.  * the hash table.
  1426.  */
  1427. int
  1428. setkrent(char *keyring)
  1429. {
  1430.     int i;
  1431.     char pubring[MAX_PATH];
  1432.  
  1433.     assert(nkr < MAXKR);
  1434.     if (keyring == NULL) {
  1435.         buildfilename(pubring, PUBLIC_KEYRING_FILENAME);
  1436.         keyring = pubring;
  1437.     }
  1438.     for (i = 0; i < nkr; ++i)
  1439.         if (strcmp(keyring, krnames[i]) == 0)
  1440.             return 0;    /* duplicate name */
  1441.     krnames[nkr++] = store_str(keyring);
  1442.     return 0;
  1443. }
  1444.  
  1445. void
  1446. endkrent(void)
  1447. {
  1448.     hashleft = strleft = 0;
  1449.     hashtbl = NULL;
  1450.     nkr = 0;
  1451.     freebufpool();
  1452. }
  1453.  
  1454. /*
  1455.  * create userid hash table, read all files set with setkrent()
  1456.  */
  1457. int
  1458. init_userhash(void)
  1459. {
  1460.     FILE *f;
  1461.     int status, i;
  1462.     byte keyID[KEYFRAGSIZE];
  1463.     char userid[256];
  1464.     byte ctb;
  1465.     int keyflag;
  1466.  
  1467.     if (!hashtbl) {
  1468.         hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *));
  1469.         memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *));
  1470.     }
  1471.     for (i = 0; i < nkr; ++i) {
  1472.         if ((f = fopen(krnames[i], FOPRBIN)) == NULL)
  1473.             continue;
  1474.         keyflag = 0;
  1475.         while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) {
  1476.             if (is_key_ctb(ctb) && user_from_keyID(keyID) == NULL)
  1477.                 keyflag = 1;
  1478.             if (keyflag && ctb == CTB_USERID) {
  1479.                 if (!hashleft) {
  1480.                     hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent));
  1481.                     hashleft = HASH_ALLOC;
  1482.                 }
  1483.                 memcpy(hashptr->keyID, keyID, KEYFRAGSIZE);
  1484.                 hashptr->userid = store_str(userid);
  1485.                 hashptr->next = hashtbl[PK_HASH(keyID)];
  1486.                 hashtbl[PK_HASH(keyID)] = hashptr;
  1487.                 ++hashptr;
  1488.                 --hashleft;
  1489.                 keyflag = 0;
  1490.             }
  1491.         }
  1492.         fclose(f);
  1493.     }
  1494.     return 0;
  1495. }
  1496.  
  1497. /*
  1498.  * memory management routines
  1499.  */
  1500.  
  1501. static void
  1502. maint_init_mem(void)
  1503. {
  1504.     pkhash = allocbuf(PK_HASHSIZE * sizeof(struct pubkey *));
  1505.     memset(pkhash, 0, PK_HASHSIZE * sizeof(struct pubkey *));
  1506. }
  1507.  
  1508. static void
  1509. maint_release_mem(void)
  1510. {
  1511.     nleft = 0;
  1512.     strleft = 0;
  1513.     pkhash = NULL;
  1514.     freebufpool();
  1515. }
  1516.  
  1517. /*
  1518.  * allocn() does the same as malloc().  Memory is allocated in chunks
  1519.  * of ALLOC_UNIT bytes, all memory can be freed by calling freebufpool().
  1520.  */
  1521. static VOID *
  1522. allocn(int size)
  1523. {
  1524.     static char *ptr;
  1525. #ifndef MSDOS    /* don't align on MSDOS to save memory */
  1526.     size = (size + 3) & ~3;
  1527. #endif
  1528.     assert(size < ALLOC_UNIT);
  1529.     if (size > nleft) {
  1530.         ptr = allocbuf(ALLOC_UNIT);
  1531.         nleft = ALLOC_UNIT;
  1532.     }
  1533.     nleft -= size;
  1534.     ptr += size;
  1535.     return ptr - size;
  1536. }
  1537.  
  1538. /*
  1539.  * store_str does the same as strdup(), but allocates memory with allocbuf()
  1540.  */
  1541. static char *
  1542. store_str(char *str)
  1543. {
  1544.     int size = strlen(str) + 1;
  1545.     if (size > ALLOC_UNIT) {
  1546.         fprintf(stderr, "store_str: string too long\n");
  1547.         return NULL;
  1548.     }
  1549.     if (size > strleft) {
  1550.         strptr = allocbuf(ALLOC_UNIT);
  1551.         strleft = ALLOC_UNIT;
  1552.     }
  1553.     strcpy(strptr, str);
  1554.     strptr += size;
  1555.     strleft -= size;
  1556.     return strptr - size;
  1557. }
  1558.  
  1559.  
  1560. static struct bufpool {
  1561.     struct bufpool *next;
  1562.     char buf[1];        /* variable size */
  1563. } *bufpool = NULL;
  1564.  
  1565. long totalsize = 0;
  1566.  
  1567. /*
  1568.  * allocate buffer, all buffers allocated with this function can be
  1569.  * freed with one call to freebufpool()
  1570.  */
  1571. static VOID *
  1572. allocbuf(int size)
  1573. {
  1574.     struct bufpool *p;
  1575.  
  1576.     p = xmalloc(size + sizeof(struct bufpool *));
  1577.     totalsize += size;
  1578.     p->next = bufpool;
  1579.     bufpool = p;
  1580.     return p->buf;
  1581. }
  1582.  
  1583. /*
  1584.  * free all memory obtained with allocbuf()
  1585.  */
  1586. static void
  1587. freebufpool(void)
  1588. {
  1589.     struct bufpool *p;
  1590.  
  1591.     if (verbose)
  1592.         fprintf(pgpout, "\nMemory used: %ldk\n", totalsize / 1024);
  1593.     totalsize = 0;
  1594.     while (bufpool) {
  1595.         p = bufpool;
  1596.         bufpool = bufpool->next;
  1597.         free(p);
  1598.     }
  1599. }
  1600.